import React, { Component } from 'react';
import {
    StyleSheet,
    View,
    Text,
    Button,
    ScrollView
} from 'react-native'
import BaseComponentF from './BaseComponentF';

var names = ['jack', 'tom', 'atom', 'ball', 'jack', 'curry', 'atom'];
var dataList = [
    { name: '小米', age: 25 },
    { name: '阿联', age: 15 },
    { name: '校长', age: 14 },
    { name: '测通', age: 38 },
    { name: '大力', age: 28 },
];
class ES6Demo extends React.Component {

    render() {
        return (
            <ScrollView>
                <Button style={Styles.btnStyle} title="let变量" onPress={() => this.testDemo04()} />
                <Button style={Styles.btnStyle} title="迭代器 for-of 循环" onPress={() => this.testDemo01()} />
                <Button style={Styles.btnStyle} title="迭代器 for-in 循环" onPress={() => this.testDemo02()} />
                <Button style={Styles.btnStyle} title="集合" onPress={() => this.testDemo03()} />
                <Button style={Styles.btnStyle} title="变量的解构赋值" onPress={() => this.testDemo05()} />
                <Button style={Styles.btnStyle} title="字符串扩展" onPress={() => this.testDemo06()} />
                <Button style={Styles.btnStyle} title="数值扩展" onPress={() => this.testDemo07()} />
                <Button style={Styles.btnStyle} title="Math对象扩展" onPress={() => this.testDemo08()} />
                <Button style={Styles.btnStyle} title="函数的扩展" onPress={() => this.testDemo09()} />
                <Button style={Styles.btnStyle} title="箭头函数" onPress={() => this.testDemo10()} />
                <Button style={Styles.btnStyle} title="数组的扩展" onPress={() => this.testDemo11()} />
                <Button style={Styles.btnStyle} title="对象的扩展" onPress={() => this.testDemo12()} />
                <Button style={Styles.btnStyle} title="Symbol" onPress={() => this.testDemo13()} />
                <Button style={Styles.btnStyle} title="Set和Map" onPress={() => this.testDemo14()} />
                <Button style={Styles.btnStyle} title="Promise" onPress={() => this.testDemo15()} />
                <Button style={Styles.btnStyle} title="类class" onPress={() => this.testDemo16()} />
            </ScrollView>
        );
    }


    /**
     * class学习
     */
    testDemo16() {

        class Point {

        }

        // alert(typeof Point); "function"
        // alert(Point == Point.prototype.constructor); "true"

        //Object.assign 可以一次性添加多个方法
        Object.assign(Point.prototype, {
            toString() {
                return 'add toString method';
            },
            toValue() {
                return 'zhudeshuai';
            }
        });
        var point = new Point();
        var point2 = new Point();
        // alert(point.toValue());

        // alert(point.__proto__.hasOwnProperty('toValue'));
        alert(point.__proto__ === point2.__proto__);



    }


    /**
     * promise
     */
    testDemo15() {
        const promise = new Promise(function (resolve, reject) {
            //...
            if (0) {
                resolve(1);
            } else {
                reject(2);
            }
        });
        promise.then(function (value) {
            //success
            alert('success');
        }, function () {
            //failed
            alert('failed');
        });

    }


    /**
     * Set和Map用法
     */
    testDemo14() {
        //set 类似数组，但是成员的值都是唯一的
        const s = new Set();
        [2, 3, 4, 5, 2, 4, 7, 6, 7, 8, 5, 4, 3, 2].forEach((x) => s.add(x));
        for (const value of s) {
            // console.log(value);
        }
        //数组去重
        // [new Set(array)]
        // Array.from(new Set(array));
        //数组与Set相互转换
        const s2 = new Set([1, 2, 3, 4, 5]);
        const array2 = Array.from(s2);
        const array3 = [...s2];

        s2.forEach((value) => {
            // console.log(value);
        });

        //数组的map和filter方法可以间接使用在Set集合上
        let s3 = new Set([1, 2, 3, 4, 5]);
        s3 = new Set([...s3].map(value => value * 2));
        // s3.forEach(x => console.log(x));

        //使用Set实现并集，交集，差集
        let s4 = new Set([2, 3, 5, 6, 8, 9]);
        let s5 = new Set([4, 3, 5, 7, 8]);

        //并集
        let union = new Set([...s4, ...s5]);
        // union.forEach(x => console.log(x));
        //交集
        let intersect = new Set([...s4].filter(x => s5.has(x)));
        // intersect.forEach(x => console.log(x));
        //差集
        let difference = new Set([...s4].filter(x => !s5.has(x)));
        difference.forEach(x => console.log(x));


        //WeakSet 成员只能是对象 ,类似java中的弱引用
        const ws = new WeakSet();
        // ws.add(1); //error
        // ws.add(Symbol());//error

        //Map学习
        const m = new Map();
        const o = { p: 'Hello World' };

        m.set(o, 'content');
        m.has(o);//true
        m.delete(o);//true
        m.has(o);//false

        const map = new Map([
            ['name', 'jack'],
            ['title', 'hello']
        ]);
        console.log(`size:${map.size}`);
        //map构造函数执行的算法
        /* const items = [[1,'zhansan'],[2,'lisi']];
        const map2 = new Map();
        items.forEach(([key,value])=>{
            map2.set(key,value);
        });
        alert(map2.size); */


        //set -> map
        const set = new Set([
            ['one', 'atom'],
            ['two', 'vscode']
        ]);

        const map2 = new Map(set);
        // alert(map2.get('two'));


        //map的遍历
        const map3 = new Map(set);
        for (const key of map2.keys()) {
            console.log(key);
        }
        for (const value of map2.values()) {
            console.log(value);
        }
        for (const item of map2.entries()) {
            console.log(item[0], item[1]);
        }
        //or
        for (const [key, value] of map2.entries()) {
            console.log(key + "--" + value);
        }
        //or
        for (const [key, value] of map2) {
            console.log(key + ":" + value);
        }

        //map转数组
        const mapArray1 = [...map3.keys()];
        const mapArray2 = [...map3.values()];
        const mapArray3 = [...map3.entries()];//[['one','atom'],['two','vscode']]
        const mapArray4 = [...map3];//[['one','atom'],['two','vscode']]

        //map本身没有map和filter方法，和set集合一样借助数组实现map和filter方法

        //forEach
        map3.forEach();


    }

    /**
     * Symbol
     */
    testDemo13() {
        //Symbol是一种原始数据类型，标识独一无二的值
        let s = Symbol();
        // alert(typeof s); symbol
        let s2 = Symbol('person');
        // alert(s2.toString());
        let s3 = Symbol('person');
        // alert(s2===s3);

        //Symbol值不能与其他类型值进行运算，包括字符串拼接
        // alert('hello' + s2); //error
        //但是可以显式转为字符串
        /* alert(String(s2));
        alert(s2.toString()); */

        //Symbol值可以转为boolean，但是不能转为数值
        // alert(Boolean(!s2));
        // alert(Number(s2));// error

        //1.实例 作为java中的枚举使用
        const marketType = {
            onsale: Symbol(),//在售
            saled: Symbol()//已售
        }

        //Symbol.for(),Symbol.keyFor()
        let a1 = Symbol.for('a');
        let a2 = Symbol.for('a');
        // alert(a1 === a2);
        // alert(Symbol.keyFor(a1));







    }


    /**
     * 对象的扩展
     */
    testDemo12() {
        //1.es6允许在对象中直接写变量，这时，属性名就是变量名，属性值就是变量的值
        const name = 'zhangsan';
        // const person = { name };
        //等同于
        const person = { name: name };
        // alert(JSON.stringify(person));

        function f(x, y) {
            return { x, y };
        }
        f(1, 2);//Object {x:1,y:2}
        // alert(JSON.stringify(f(1, 2)));
        //方法同样可以简写
        const o = {
            method() {
                return 'Hello';
            }
        }
        //等同于
        const o2 = {
            method: function () {
                return 'Hello';
            }
        }



    }


    /**
     * 数组的扩展
     */
    testDemo11() {
        //1.扩展运算符作用域rest参数相反
        console.log(...[2, 3, 4, 5]);
        console.log(1, ...[2, 3, 4], 5, 6);

        //2.替代函数apply方法
        function f(x, y, z) {
            console.log(`x=${this.x},y=${y},z=${z}`);
        }
        const args = [1, 2, 3];
        f.apply(null, args);

        //数据克隆
        const a1 = [1, 2, 3];
        const a2 = [...a1];
        //或者
        const [...a3] = a1;

        //合并数组
        a4 = [...a1, ...a2, ...a3];
        console.log(...a4);

        //与解构赋值结合
        const list = ['a', 'b', 'c', 'd'];
        [a, ...rest] = list;//注意：扩展运算符用于数组赋值，必须放在最后一位
        console.log(...rest);
        // alert(a);
        //字符串转成数组
        // alert([...'hellow']);
        // alert([...'你好a'].length); 3

        /**
         * 可以正确返回字符串长度，包括四个字节的Unicode字符
         * @param {目标字符串} str 
         */
        function length(str) {
            return [...str].length;
        }

        //任何Iterator接口的对象都可以转为真正的数组
        /* let nodeList = document.querySelectorAll('div');
        let array = [...nodeList]; */

        //数组find()和findIndex()
        let a = [1, 2, 3, 4, -9, 0].find((n) => n < 0);//-9
        let aIndex = [1, 2, 3, 4, -9, 0].findIndex((n) => n < 0);//4
        // alert(aIndex);

        //fill(插入的元素，开始位置，结束位置)方法
        let b = ['a', 'b', 'c'].fill(6, 1, 3);
        // alert(b);

        //entries(),keys(),values() 类似于java的map遍历，其中key是角标
        let c = ['a', 'b', 'c'];
        for (const index of c.keys()) {
            console.log(index);
        }
        //不兼容
        /* for (const value of c.values()) {
            console.log(value);
        } */
        for (const [index, value] of c.entries()) {
            console.log(`${index}:${value}`);
        }

        //includes()   indexOf()
        // alert(c.indexOf('c'));

        //判断当前环境是否支持该方法
        // alert(Array.prototype.values?'support':'not support');
        let result = c.some((value, index, array) => {
            return value === 'a';
        });
        // alert(result);

        const getArrayValues = (() => {
            return Array.prototype.values
                ? (array) => array.values()
                : (array) => array
        }
        )();
        /* for (const value of getArrayValues(c)) {
            console.log(value);
        } */




    }

    /**
     * 箭头函数学习
     */
    testDemo10() {

        var f = v => v;
        //等同于
        var f = function (v) {
            return v;
        }

        var f = () => 5;
        //等同于
        var f = function () { return 5 };

        var sum = (x, y) => x + y;
        //等同于
        var sum = function (x, y) {
            return x + y;
        }

        //与解构结合使用
        const fullName = ({ firstName, lastName }) => firstName + ' ' + lastName;
        //等同于
        function full(person) {
            return person.firstName + ' ' + person.lastName;
        }

        const isEven = n => n % 2 == 0;
        console.log(isEven(4));

        let a = [1, 2, 3].map(x => x * x);
        console.log(a);

        let b = [4, 3, 7, 1, 6].sort((x, y) => x - y);
        console.log(b);

        //rest参数与箭头函数结合
        const numbers = (...nums) => nums;
        console.log(numbers(3, 4, 5, 6, 7));

        const headAndTail = (head, ...nums) => [head, nums];
        console.log(headAndTail(9, 23, 4, 5, 7));//[9,[23,4,5,7]]

        //箭头函数this使用
        function zhu() {
            setTimeout(() => {
                //this绑定的是该函数定义时的作用域，而不是运行时
                console.log('id:', this.id);
            }, 100);
        }
        var id = 21;
        // zhu.call({ id: 666 });


        function Timer() {
            this.s1 = 0;
            this.s2 = 0;

            setInterval(() => this.s1++, 1000);

            setInterval(function () {
                this.s2++;
                console.log(`---${this.s2}--`);
            }, 1000);
        }
        // Timer();
        // new Timer();
        // var timer = new Timer();

        // setTimeout(() => console.log('s1:', timer.s1), 3100);
        // setTimeout(() => console.log('s2:', timer.s2), 3100);

        function foo() {
            setTimeout(() => {
                console.log('id:', this.id);
            }, 1000);
        }
        //等价于
        function foo() {
            var _this = this;
            setTimeout(function () {
                console.log('id:', _this.id);
            }, 1000);
        }


        //arguments
        function foo() {
            setTimeout(() => {
                console.log('args:', arguments);//arguments使用的最外层foo的参数
            }, 100);
        }
        foo(1, 3, 5, 6);

        //bind
        //箭头函数没有自己的this，所以bind方法无效，内部this指向外部的this
        (function () {
            return [
                (() => this.x).bind({ x: 'inner' })()
            ];
        }).call({ x: 'outer' });



        //双冒号运算符(函数绑定运算符)
        //将左边的对象作为上下文环境，绑定到右边的函数上面

        //尾递归


    }



    /**
     * 函数的扩展
     */
    testDemo09() {
        //es6允许为函数的参数设置默认值
        function log(x, y = '默认值') {
            console.log(`x=${x},y=${y}`);
        }
        // log('Hello');

        let x = 99;
        function foo(p = x + 1) {
            console.log(p);
        }
        // foo();
        x = 100;
        //每次都是会去加载参数表达式
        // foo();

        //函数参数默认值与解构配合使用
        function m1({ x, y } = { x: 10, y: 10 }) {
            console.log(`x=${x},y=${y}`);
        }
        function m2({ x = 10, y = 10 } = {}) {
            console.log(`x=${x},y=${y}`);
        }

        // m1();
        // m2();

        // m1({x:8});
        // m2({x:8});

        //默认参数的位置，最好默认参数放到最后一个，不然默认参数没法避免赋值
        function m3(x = 1, y) {
            return [x, y];
        }

        m3();

        //函数的length
        // console.log((function (x = 1, y, z, ) { }).length);
        // console.log((function (x, y, z) { }).length);

        //作用域,函数的参数会形成一个单独的作用域，所以不会影响外部和函数内部定义的变量
        function m4(x, y = x) {
            console.log(y);
        }
        // console.log(x);
        // m4(2);

        //函数默认值解决必要参数问题
        function throwIfMissing() {
            throw new Error('Missing parameter');
        }

        function m5(x = throwIfMissing()) {
            console.log(x);
        }
        // m5();

        //rest参数
        function m6(...values) {
            let sum = 0;
            for (const value of values) {
                sum += value;
            }
            console.log(sum);
        }
        // m6(1,2,3,4,5);

        //函数name属性
        /* console.log(m6.name);
        var m7 = function(){};
        console.log(m7.name);
        console.log((new Function).name); */





    }



    /**
     * Math对象扩展
     */
    testDemo08() {
        //Math.trunc()  用于去除一个数的小数部分，返回整数部分
        /* console.log(Math.trunc(5.9909));//5
        console.log(Math.trunc('5.0094'));//5
        console.log(Math.trunc(true));//1
        console.log(Math.trunc(null));//0 */

        //Math.sign() 判断一个数是正数、负数、还是零
        console.log(Math.sign(-6));
        console.log(Math.sign(9));
        console.log(Math.sign('88'));
    }



    /**
     * 数值扩展
     */
    testDemo07() {
        console.log(Number.isFinite(true));
        console.log(Number.isNaN('true' / 0));//true
        //类型转换
        let num01 = Number.parseInt('99.9');
        console.log(`number01:${num01}`);
        //该方法不能用于大数据精确判断
        let num02 = Number.isInteger(3.00000000000000000000000000000000000000000000002);
        console.log(num02);

        let num03 = 0.1 + 0.2;
        console.log(num03);

        /**
         * 判断两个浮点数是否相等，差值在某一个范围之内
         * @param {*} left 
         * @param {*} right 
         */
        function withinErrorMargin(left, right) {
            return Math.abs(left - right) < Number.EPSILON * Math.pow(2, 2);
        }

        console.log(withinErrorMargin(num03, 0.3));

        //js表示数字的极限
        console.log(`最大值：${Number.MAX_SAFE_INTEGER}`);
        console.log(`最小值：${Number.MIN_SAFE_INTEGER}`);

        console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER));


    }


    /**
     * 字符串扩展
     */
    testDemo06() {
        let s = '𠮷a';
        for (let ch of s) {
            console.log(ch + ',' + ch.codePointAt(0) > 0xFFFF);
        }
        console.log(s.length);
        console.log(s.charAt(0));

        let url = 'http://www.che168.com';
        console.log(url.indexOf(':'));
        console.log(url.startsWith('https'));
        console.log(url.startsWith('http'));
        console.log(url.endsWith('com'));

        //padStart  padEnd
        console.log('x'.padStart(3, 'a'));
        console.log('x'.padEnd(3, 'end'));
        console.log('09-12'.padStart(10, 'YYYY-MM-DD'));
    }


    /**
     * 变量的解构和赋值
     */
    testDemo05() {
        //1.交换变量的值
        let x = 1;
        let y = 2;
        [x, y] = [y, x];
        // console.log(`x=${x},y=${y}`);
        //2.从函数返回多个值
        function example() {
            return [1, 2, 3];
        }
        //解构数组，按顺序解构
        let [a, b, c] = example();
        // console.log(`a=${a},b=${b},c=${c}`);

        function returnObject() {
            return { name: '张三', age: 28 };
        }
        //解构对象，按属性名解构
        let { age, name } = returnObject();
        // console.log(`name=${name},age=${age}`);

        //3、函数参数的定义，同理数组是有序获取，对象是对应属性获取
        function logArray([x, y, z]) {
            console.log(`x=${x},y=${y},z=${z}`);
        }
        // logArray([4,5]);
        function logObject({ x, y, z }) {
            console.log(`x=${x},y=${y},z=${z}`);
        }
        // logObject({ y: 7, x: 6, z: 8 });

        //4、提取JSON数据
        let jsonData = {
            status: 1,
            message: 'success',
            data: [23, 455]
        };

        let { status, message, data } = jsonData;
        // console.log(`status=${status},message=${message},data=${data}`);


        //5、函数参数的默认值
        function defaultValueM(url, {
            name = '小明',
            age = 10
        }) {
            console.log(`name=${name},age=${age}`);
        }
        // defaultValueM('http://www.baidu.com',{age:29});

        //6、遍历map结构
        const map = new Map();
        map.set('first', 'hello');
        map.set('second', 'world');

        for (let [key, value] of map) {
            console.log(`key=${key},value=${value}`);
        }
        //获取键名
        for (let [key] of map) {
            console.log(`key=${key}`);
        }
        //获取键值
        for (let [, value] of map) {
            console.log(`value=${value}`);
        }
    }


    testDemo04() {
        //let和const命令
        {
            let a = 5;
            var b = 8;
        }
        // console.log(JSON.stringify(b));

        var a = [];
        for (let i = 0; i < 10; i++) {
            a[i] = function () {
                console.log(i);
            }
        }
        // a[9]();
        // a[1]();

        // console.log(bar);
        // let bar = 2;

        // var tmp = 12;
        if (true) {
            tmp = 'aaa';
            console.log(tmp);
            let tmp = 'ccc';
            console.log(tmp);

            var tmp = 2;
        }



    }

    testDemo01() {
        //迭代器 for-of 循环
        for (const name of names) {
            console.log('for-of:' + name);
        }

        for (const { name, age } of dataList) {
            console.log('name:' + name + ',age:' + age);
        }

    }
    testDemo02() {
        //迭代器 for-in 循环
        for (const index in names) {
            console.log('for-in:' + names[index]);
        }
    }

    testDemo03() {
        //Set集合 包含性检测速度优化 不能提供索引
        var uniqueWords = new Set(names);
        for (const name of uniqueWords) {
            console.log('set集合：' + name);
        }

        console.log('has curry:' + uniqueWords.has('curry'));
        console.log('删除方法：删除jack');
        var delResult = uniqueWords.delete('jack');
        for (const name of uniqueWords) {
            console.log('set集合：' + name);
        }

        //map集合
        var myMap = new Map();
        for (var i = 0; i < 5; i++) {
            myMap.set(i, `M:${i}`);
        }
        for (const [index, name] of myMap) {
            console.log(`index:${index},name:${name}`);
        }


    }
}

export default BaseComponentF(ES6Demo);

const Styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    btnStyle: {
        color: '#0000ff'
    }
});